package com.wzxl.config.shiro;

import com.wzxl.bean.User;
import com.wzxl.service.UserService;
import com.wzxl.utils.ConstantUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;

import java.util.Set;

/**
 * @author rxbyes
 * @version V1.0
 * @package com.wzxl.shiro
 * @description: TODO ( 资源身份认证 )
 * @date 2017 下午11:17
 */
public class DemoAuthorizingRealm extends AuthorizingRealm {

    private static final Logger LOGGER = LoggerFactory.getLogger(DemoAuthorizingRealm.class);

    @Autowired
    private UserService accountService;


    public DemoAuthorizingRealm() {
        this.setCachingEnabled(false);
    }

    /**
     * 认证信息.(身份验证)
     *
     * @param token
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {

        LOGGER.info("登录信息：ShiroRealm.doGetAuthenticationInfo()");
        User user = new User();
        user.setUsername(token.getPrincipal().toString());
        User account = accountService.login(user);

        if (StringUtils.isEmpty(account)) {
            LOGGER.error("登录用户名错误,{}", user.getUsername());
            throw new UnknownAccountException("用户名错误");
        }

        if (StringUtils.isEmpty(account.getState()) || ConstantUtils.STRING_TWO.equals(account.getState().toString())) {
            LOGGER.error("登录账号已停用,{}", user.getUsername());
            throw new DisabledAccountException("账号已停用");
        }

        /**
         * 交给AuthenticatingRealm使用CredentialsMatcher进行密码匹配，
         *
         * user 登录用户
         * user.password 密码
         * salt 盐值，增强密码加密
         * user.username realm name
         */
        SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(
                account,
                account.getPassword(),
                ByteSource.Util.bytes(account.getCredentialsSalt()),
                account.getUsername()
        );
        return authenticationInfo;
    }


    /**
     * 此方法调用  hasRole,hasPermission的时候才会进行回调.
     * <p>
     * 权限信息.(授权):
     * 1、如果用户正常退出，缓存自动清空；
     * 2、如果用户非正常退出，缓存自动清空；
     * 3、如果我们修改了用户的权限，而用户不退出系统，修改的权限无法立即生效,需要手动编程进行实现；放在service进行调用
     * 在权限修改后调用realm中的方法，realm已经由spring管理，所以从spring中获取realm实例，调用clearCached方法；
     * :Authorization 是授权访问控制，用于对用户进行的操作授权，证明该用户是否允许进行当前操作，如访问某个链接，某个资源文件等。
     *
     * @param principals
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) throws AuthenticationException {
       /*
        * 当没有使用缓存的时候，不断刷新页面的话，这个代码会不断执行，
        * 当其实没有必要每次都重新设置权限信息，所以我们需要放到缓存中进行管理；
        * 当放到缓存中时，这样的话，doGetAuthorizationInfo就只会执行一次了，
        * 缓存过期之后会再次执行。
        */
        LOGGER.info("后台权限校验-->ShiroRealm.doGetAuthorizationInfo()");

        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
        Account account = (Account) principals.getPrimaryPrincipal();
        Set<String> menus = null;

        authorizationInfo.addStringPermissions(menus);
        return authorizationInfo;
    }

    /**
     * 清除缓存
     */
    public void clearCached() {
        PrincipalCollection principals = SecurityUtils.getSubject().getPrincipals();
        super.clearCache(principals);
    }



    /**
     * char 转换 String
     *
     * @param var
     * @return
     */
    public static String convertCharToString(Object var) {
        if (var instanceof char[]) {
            char[] var1 = (char[]) var;
            return new String(var1);
        }
        return null;
    }
}
